package me.dwk.dandan.function.functions;

import java.util.Collection;
import java.util.LinkedList;
import java.util.List;

import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;

import lombok.extern.slf4j.Slf4j;
import me.dwk.dandan.function.AbstractFunction;
import me.dwk.dandan.function.CompoundVariable;
import me.dwk.dandan.function.ThreadVariables;
import me.dwk.dandan.function.exception.InvalidVariableException;

/**
 * Provides a RandomString function which returns a random String of length
 * (first argument) using characters (second argument)
 *
 * @since 2.6
 */
@Slf4j
public class RandomString extends AbstractFunction {

	private static final List<String>	desc	= new LinkedList<>();

	private static final String			KEY		= "__RandomString";		//$NON-NLS-1$

	static {
		desc.add("Random string length"); //$NON-NLS-1$
		desc.add("Chars to use for random string generation"); //$NON-NLS-1$
		desc.add("Name of variable in which to store the result (optional)"); //$NON-NLS-1$
	}

	private CompoundVariable[]	values;

	private static final int	MAX_PARAM_COUNT	= 3;

	private static final int	MIN_PARAM_COUNT	= 1;

	private static final int	CHARS			= 2;

	private static final int	PARAM_NAME		= 3;

	/**
	 * No-arg constructor.
	 */
	public RandomString() {
		super();
	}

	/** {@inheritDoc} */
	@Override
	public String execute() throws InvalidVariableException {

		int length = Integer.parseInt(values[0].execute());

		String charsToUse = null;// means no restriction
		if (values.length >= CHARS) {
			charsToUse = (values[CHARS - 1]).execute().trim();
			if (charsToUse.length() <= 0) { // empty chars, return to null
				charsToUse = null;
			}
		}

		String myName = "";//$NON-NLS-1$
		if (values.length >= PARAM_NAME) {
			myName = (values[PARAM_NAME - 1]).execute().trim();
		}

		String myValue = null;
		if (StringUtils.isEmpty(charsToUse)) {
			myValue = RandomStringUtils.random(length);
		} else {
			myValue = RandomStringUtils.random(length, charsToUse);
		}

		if (myName.length() > 0) {
			ThreadVariables vars = getVariables();
			if (vars != null) {// Can be null if called from Config item testEnded() method
				vars.put(myName, myValue);
			}
		}

		if (log.isDebugEnabled()) {
			String tn = Thread.currentThread().getName();
			log.debug(tn
							+ " name:" //$NON-NLS-1$
							+ myName
							+ " value:" //$NON-NLS-1$
							+ myValue);
		}

		return myValue;
	}

	/** {@inheritDoc} */
	@Override
	public void setParameters(Collection<CompoundVariable> parameters) throws InvalidVariableException {
		checkParameterCount(parameters, MIN_PARAM_COUNT, MAX_PARAM_COUNT);
		values = parameters.toArray(new CompoundVariable[parameters.size()]);
	}

	/** {@inheritDoc} */
	@Override
	public String getReferenceKey() {
		return KEY;
	}

	/** {@inheritDoc} */
	@Override
	public List<String> getArgumentDesc() {
		return desc;
	}
}
